#!/bin/bash -e
#   * compile instructions: put this file in
#   *         `steamapps/common/Dyson Sphere Program/CustomMod`
#   * folder, open a terminal in the same folder, and execute:
#   *
#   * ```
#   *     chmod +x ${file}.cs
#   *     ./${file}.cs
#   * ```
#   *
#   * then the mod will be compiled automatically.
#   *
#   * Here we wrote a shebang like file, which is correct
#   * in my computer (Manjaro XFCE), if such script do not work
#   * in your computer, you could just try the instructions below :

export IFS=$'\n' # to disable the annoying space.
export DOTNET=dotnet # the location of the DOTNET executable file.
[ -z "$DOTNET_CSC_DLL" ] && export DOTNET_CSC_DLL=`\ls /usr/share/dotnet/sdk/*/Roslyn/bincore/csc.dll` # In manjaro, the csc.dll is located in /usr/share/dotnet/sdk/*/Roslyn/bincore/csc.dll

__MODE_VERBOSE=81 # is the line number of "#define VERBOSE", may be modified
__MODE_DEBUG__=$((__MODE_VERBOSE+1))
__MODE_RELEASE=$((__MODE_DEBUG__+1))

case $1 in
    V)       _MODE__SELECT_=$__MODE_VERBOSE     ;;
    v)       _MODE__SELECT_=$__MODE_VERBOSE     ;;
    VERBOSE) _MODE__SELECT_=$__MODE_VERBOSE     ;;
    verbose) _MODE__SELECT_=$__MODE_VERBOSE     ;;
    D)       _MODE__SELECT_=$__MODE_DEBUG__     ;;
    d)       _MODE__SELECT_=$__MODE_DEBUG__     ;;
    DEBUG)   _MODE__SELECT_=$__MODE_DEBUG__     ;;
    debug)   _MODE__SELECT_=$__MODE_DEBUG__     ;;
    *)       _MODE__SELECT_=$__MODE_RELEASE     ;;
esac

# export GAME_NAME="${0%\.cs}" # now, file name should be equals to ${GAME_NAME}.cs, the benefit is, we could only change the name, rather than change filename and $GAME_NAME.
# export GAME_NAME="$(basename `pwd`)" # now, file name should be equals to ${GAME_NAME}.cs, the benefit is, we could only change the name, rather than change filename and $GAME_NAME.
export GAME_NAME="Big Bia"
export FILE_NAME="$0"
export GAME_DIR="$GAME_NAME"                                # might be modified, "$GAME_NAME" cover most of the cases.
export ASSEMBLY="Assembly-CSharp"                           # might be modified
export PLUGIN_ID="Neutron3529.Cheat"                        # should be modified
export NAMESPACE_ID="Neutron3529.Cheat"                     # should be modified
export GAME_BASE_DIR="common/$GAME_DIR"                     # should modify GAME_DIR instead since GAME_DIR == GAME_NAME is almost always true.

( yes "" | head -n $_MODE__SELECT_ | head -n-1  ; tail $FILE_NAME -n+$_MODE__SELECT_ ) | sed s/%%NAMESPACE_ID%%/${NAMESPACE_ID}/g | sed s/%%PLUGIN_ID%%/${PLUGIN_ID}/g | $DOTNET $DOTNET_CSC_DLL -nologo -t:library \
  -r:"${GAME_BASE_DIR}/BepInEx/core/BepInEx.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/0Harmony.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/BepInEx.Harmony.dll" \
  `[ -e "${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/netstandard.dll" ] && echo "-r:\"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/netstandard.dll\""` \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/System.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/System.Core.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.AIModule.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.CoreModule.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.UI.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/mscorlib.dll" \
  $(for i in "${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/$ASSEMBLY"*.dll ; do echo -e "-r:\"$i\"\n" ; done) \
  -out:"${GAME_BASE_DIR}/BepInEx/plugins/${FILE_NAME%.*}".dll \
  -optimize `[ "$_MODE__SELECT_" == "$__MODE_DEBUG__" ] && echo -debug` \
  - && rm -f "${GAME_BASE_DIR}/BepInEx/config/${PLUGIN_ID}.cfg";

if [ -n "$2" ]; then
    git add ${FILE_NAME}
    case $2 in
        R) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        r) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        RANDOM) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        random) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        U) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        u) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        UPLOAD) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        upload) git commit -am "`curl -s https://whatthecommit.com/index.txt`" ;;
        *) git commit -am "$2" ;;
    esac
    git push
fi
exit

#define VERBOSE // the line of __MODE_VERBOSE
#define DEBUG



using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;

using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

namespace %%NAMESPACE_ID%%
{
    [BepInPlugin("%%PLUGIN_ID%%", "%%NAMESPACE_ID%%", "0.1.0")]
    public class Cheat : BaseUnityPlugin {
#if DEBUG
        public static Action<string> logger;
#else
        public static void logger(string s){}
#endif
        public static List<Vector3Int> ATKRANGE=new List<Vector3Int>(){
                    new Vector3Int(-2,-2, 0),
                    new Vector3Int(-2,-1, 0),
                    new Vector3Int(-2, 0, 0),
                    new Vector3Int(-2, 1, 0),
                    new Vector3Int(-2, 2, 0),
                    new Vector3Int(-1,-2, 0),
                    new Vector3Int(-1,-1, 0),
                    new Vector3Int(-1, 0, 0),
                    new Vector3Int(-1, 1, 0),
                    new Vector3Int(-1, 2, 0),
                    new Vector3Int( 0,-2, 0),
                    new Vector3Int( 0,-1, 0),
                    new Vector3Int( 0, 0, 0),
                    new Vector3Int( 0, 1, 0),
                    new Vector3Int( 0, 2, 0),
                    new Vector3Int( 1,-2, 0),
                    new Vector3Int( 1,-1, 0),
                    new Vector3Int( 1, 0, 0),
                    new Vector3Int( 1, 1, 0),
                    new Vector3Int( 1, 2, 0),
                    new Vector3Int( 2,-2, 0),
                    new Vector3Int( 2,-1, 0),
                    new Vector3Int( 2, 0, 0),
                    new Vector3Int( 2, 1, 0),
                    new Vector3Int( 2, 2, 0)
                };
        void Start() {
            var harmony=new Harmony("%%PLUGIN_ID%%");
#if DEBUG
            logger=Logger.LogInfo;
#endif
            logger("叮~");
            if(Config.Bind("config", "ouxiang_wunv_powerful", true, "偶像歌手/舞女变成最强英雄/随从").Value){
                harmony.PatchAll(typeof(CardLogic_OnAttack));
                harmony.PatchAll(typeof(CardLogic_OnCardUseSkill));
                logger("ouxiang_wunv_powerful patched");
            }
            logger("您的修改器已启动");
        }
        class CardLogic_OnAttack {
            static IEnumerable<MethodBase> TargetMethods()
            {
                foreach(string str in new string[]{"OnAfterAttack"}){
                    MethodInfo m=typeof(OuXiangGeShouCardLogic).GetMethod(str,(BindingFlags)(-1));
                    if(m!=null){
                        yield return m;
                    }
                }
                foreach(string str in new string[]{"OnBeforeAttack"}){
                    MethodInfo m=typeof(WuNvCardLogic).GetMethod(str,(BindingFlags)(-1));
                    if(m!=null){
                        yield return m;
                    }
                }
                yield return typeof(WangZiCardLogic).GetMethod("OnAfterAttack",(BindingFlags)(-1));
            }
            static bool Prepare(MethodBase __originalMethod){
                if(__originalMethod==null){
                    logger("first prepare, should return true.");
                    return true;
                }
                bool non_generic=!__originalMethod.IsGenericMethod;
                bool not_getter_setter=!(__originalMethod.Name.Length>4 && ((__originalMethod.Name[0]=='g' || __originalMethod.Name[0]=='s') && __originalMethod.Name[1]=='e' && __originalMethod.Name[2]=='t' && __originalMethod.Name[3]=='_'));
                logger("prepare "+__originalMethod+", non_generic="+non_generic+", not_getter_setter="+not_getter_setter);
                return non_generic && not_getter_setter;
            }
            static System.Collections.IEnumerator Postfix(System.Collections.IEnumerator __result, MethodBase __originalMethod, CardData player) {
                if(!player.HasTag(TagMap.随从))yield break;
                player.NextAttackTimes=2;
                player.NextAttackCRIT=100;
                player.ATKRange=5;
                player.NextATK=100;
                player.HP=player.MaxHP*2;
                player.Armor=9;
                if(player.AttackExtraRange.Count<10)player.AttackExtraRange=new List<Vector3Int>(ATKRANGE);
                while(__result.MoveNext())yield return __result.Current;
                yield break;
            }
        }
        class CardLogic_OnCardUseSkill {
            static IEnumerable<MethodBase> TargetMethods()
            {
                foreach(string str in new string[]{"OnCardAfterUseSkill"}){
                    MethodInfo m=typeof(OuXiangGeShouCardLogic).GetMethod(str,(BindingFlags)(-1));
                    if(m!=null){
                        yield return m;
                    }
                }
                foreach(string str in new string[]{"OnCardBeforeUseSkill"}){
                    MethodInfo m=typeof(WuNvCardLogic).GetMethod(str,(BindingFlags)(-1));
                    if(m!=null){
                        yield return m;
                    }
                }
            }
            static bool Prepare(MethodBase __originalMethod){
                if(__originalMethod==null){
                    logger("first prepare, should return true.");
                    return true;
                }
                bool non_generic=!__originalMethod.IsGenericMethod;
                bool not_getter_setter=!(__originalMethod.Name.Length>4 && ((__originalMethod.Name[0]=='g' || __originalMethod.Name[0]=='s') && __originalMethod.Name[1]=='e' && __originalMethod.Name[2]=='t' && __originalMethod.Name[3]=='_'));
                logger("prepare "+__originalMethod+", non_generic="+non_generic+", not_getter_setter="+not_getter_setter);
                return non_generic && not_getter_setter;
            }
            static System.Collections.IEnumerator Postfix(System.Collections.IEnumerator __result, MethodBase __originalMethod, CardData user) {
                if(!user.HasTag(TagMap.随从))yield break;
                user.NextAttackTimes=2;
                user.NextAttackCRIT=100;
                user.ATKRange=5;
                user.NextATK=100;
                user.HP=user.MaxHP*2;
                user.Armor=9;
                if(user.AttackExtraRange.Count<10)user.AttackExtraRange=new List<Vector3Int>(ATKRANGE);
                while(__result.MoveNext())yield return __result.Current;
                yield break;
            }
        }
    }
}

